package com.fcy.teamwork.security

import com.fcy.teamwork.App
import com.fcy.teamwork.base.log
import okhttp3.OkHttpClient
import java.io.IOException
import java.io.InputStream
import java.security.KeyStore
import java.security.KeyStoreException
import java.security.NoSuchAlgorithmException
import java.security.SecureRandom
import java.security.cert.Certificate
import java.security.cert.CertificateException
import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate
import java.util.*
import javax.net.ssl.*

/**
 * 创建只信任指定证书的TrustManager
 * @param inputStream：证书输入流
 * @return
 */
private fun getInputStreamFromAsset(): InputStream {
    var inputStream: InputStream? = null
    try {
        inputStream = App.application.assets.open("client.cer")
    } catch (e: IOException) {
        e.printStackTrace()
    }
    checkNotNull(inputStream)
    return inputStream
}

private fun createTrustCustomTrustManager(inputStream: InputStream = getInputStreamFromAsset()): X509TrustManager? {
    try {
        val certificateFactory: CertificateFactory = CertificateFactory.getInstance("X.509")
        val keyStore = KeyStore.getInstance(KeyStore.getDefaultType())
        keyStore.load(null)

        val certificate: X509Certificate =
            certificateFactory.generateCertificate(inputStream) as X509Certificate
        log(
            """
            ca=${certificate.subjectDN}
            key=${certificate.publicKey}
        """.trimIndent()
        )
        //将证书放入keystore中
        val certificateAlias = "ca"
        keyStore.setCertificateEntry(certificateAlias, certificate)
        inputStream.close()
        val trustManagerFactory: TrustManagerFactory =
            TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
        trustManagerFactory.init(keyStore)
        val trustManagers: Array<TrustManager> =
            trustManagerFactory.trustManagers
        check(!(trustManagers.size != 1 || trustManagers[0] !is X509TrustManager)) {
            ("Unexpected default trust managers:"
                    + Arrays.toString(trustManagers))
        }
        return trustManagers[0] as X509TrustManager
    } catch (e: java.lang.Exception) {
        e.printStackTrace()
    }
    return null
}

/**
 * 创建既信任自签名证书又信任系统自带证书的TrustManager
 */
private fun createTrustCustomAndDefaultTrustManager(): X509TrustManager? {
    try {
        // 获取信任系统自带证书的TrustManager
        val systemTrustManager = getSystemTrustManager()
        // 获取信任自签名证书的TrustManager
        val selfTrustManager: X509TrustManager =
            createTrustCustomTrustManager()
                ?: throw java.lang.IllegalStateException("自签名证书出现异常")
        return object : X509TrustManager {
            @Throws(CertificateException::class)
            override fun checkClientTrusted(chain: Array<X509Certificate?>?, authType: String?) {
                systemTrustManager!!.checkClientTrusted(chain, authType)
            }

            @Throws(CertificateException::class)
            override fun checkServerTrusted(chain: Array<X509Certificate?>?, authType: String?) {
                try {
                    // 默认使用信任自签名证书的TrustManager验证服务端身份
                    selfTrustManager.checkServerTrusted(chain, authType)
                } catch (e: CertificateException) {
                    // 此处使用系统自带SSL证书验证服务端身份
//                    systemTrustManager!!.checkServerTrusted(chain, authType)
                }
            }

            override fun getAcceptedIssuers(): Array<X509Certificate> {
                return systemTrustManager!!.acceptedIssuers
            }
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
    return null
}

/**
 * 创建信任系统自带证书的TrustManager
 */
@Throws(NoSuchAlgorithmException::class, KeyStoreException::class)
private fun getSystemTrustManager(): X509TrustManager? {
    val tmf = TrustManagerFactory
        .getInstance(TrustManagerFactory.getDefaultAlgorithm())
    tmf.init(null as KeyStore?)
    for (tm in tmf.trustManagers) {
        if (tm is X509TrustManager) {
            return tm
        }
    }
    return null
}

class NoneFilterHostNameVerifier : HostnameVerifier {
    override fun verify(hostname: String?, session: SSLSession?): Boolean {
        return true
    }
}

fun OkHttpClient.Builder.initSSL(
    trustManager: X509TrustManager? = createTrustCustomAndDefaultTrustManager()
): OkHttpClient.Builder {
    checkNotNull(trustManager)
    val sslContext = SSLContext.getInstance("SSL")
    sslContext.init(null, arrayOf(trustManager), SecureRandom())
    sslSocketFactory(sslContext.socketFactory, trustManager)
    return this
}